
#pragma once

#include "atr/algorithm.hpp"
#include "atr/functional.hpp"

#include "atr/containers/operations/merge.hpp"
#include "atr/containers/operations/remove.hpp"
#include "atr/containers/operations/reverse.hpp"
#include "atr/containers/operations/sort.hpp"
#include "atr/containers/operations/splice.hpp"
#include "atr/containers/operations/unique.hpp"

namespace atr {

/**
 * @brief Namespace only for internal use of atr library
 * @details Please don't use this namespace outside the atr library. IF you REALLY need to - do it with special care.
 */
namespace __ {

template <template <class ...> class Base, typename ... Types>
struct __operations
{
private:
    template <class ToRemove>
    struct __predicate
    {
        template <class T> using remove = typename equal<ToRemove, T>::type;
    };
public:

    template <class Position, class Other, class ... Iterators>
    using splice = typename __::__splice<Base<Types...>,
                                         Position, Other, Iterators...>::type;

    template <template <class> class Predicate>
    using remove_if = typename __::__remove_if<Predicate,
                                               Base<>,
                                               Base<bool, Types...>,
                                               false>::type;

    template <class ToRemove>
    using remove = remove_if<__predicate<ToRemove>::template remove>;

    template <template <class, class> class BinaryPredicate = equal>
    using unique = typename __::__unique<BinaryPredicate,
                                         Base<>,
                                         bool,
                                         Base<Types...>,
                                         false>::type;

    template <class Other, template <class, class> class Comparator = less>
    using merge = typename __::__merge<Base<>, Base<bool, Types...>,
                                       Other,
                                       Comparator,
                                       true>::type::pop_front;

    template <template <class, class> class Comparator = less>
    using sort = typename __::__sort<Base<>,
                                     Base<Types...>,
                                     Comparator,
                                     sizeof ... (Types) == 0>::type;

    using reverse = typename __reverse<Base<>, Base<Types...>>::type;

};

} // namespace __
} // namespace atr